

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "../../include/list.h"
#include "../../include/set.h"

static void print_set(const set_t *set)
{
	list_node_t *n;
	unsigned int idx = 0;

	fprintf(stdout, "set size is %d\n", set_size(set));

	for (n = list_head(set); n != NULL; n = list_next(n))
	{
		fprintf(stdout, "set[%d] = %d\n", idx, *(int *)list_data(n));
		idx++;
	}

	return;
}


static int match_int(const void *key1, const void *key2)
{
	return !memcmp(key1, key2, sizeof(int));
}


int main(int argc, char *argv[])
{
	set_t set, set1, set2;
	int *data;
	int ret, i;
	unsigned int idx;

	set_init(&set, match_int, free);

	fprintf(stdout, "inserting 10 elements\n");
	for (idx = 0; idx < 10; idx++)
	{
		if (!(data = (int *)malloc(sizeof(int))))
			return 1;

		*data = idx + 1;
		ret = set_insert(&set, data);
		if (ret < 0)
			return 1;
		else if (ret == 1){
			free(data);
		}
	}

	print_set(&set);

	fprintf(stdout, "inserting same elements again\n");
	for (idx = 0; idx < 10; idx++)
	{
		if (!(data = (int *)malloc(sizeof(int))))
			return 1;

		*data = idx + 1;
		ret = set_insert(&set, data);
		if (ret < 0)
			return 1;
		else if (ret == 1){
			free(data);
		}
	}

	print_set(&set);

	fprintf(stdout, "inserting 100 and 200\n");
	if (!(data = (int *)malloc(sizeof(int))))
		return -1;
	*data = 100;
	ret = set_insert(&set, data);
	if (ret < 0)
		return 1;
	else if (ret == 1)
		free(data);

	if (!(data = (int *)malloc(sizeof(int))))
		return -1;

	*data = 200;
	ret = set_insert(&set, data);
	if (ret < 0)
		return 1;
	else if (ret == 1)
		free(data);

	print_set(&set);

	fprintf(stdout, "removing 100 5 and 10\n");
	ret = 100;
	data = &ret;
	if (!set_remove(&set, (void **)&data))
		free(data);

	ret = 5;
	data = &ret;
	if (!set_remove(&set, (void **)&data))
		free(data);

	ret = 10;
	data = &ret;
	if (!set_remove(&set, (void **)&data))
		free(data);

	print_set(&set);

	fprintf(stdout, "remove all elements\n");
	while (set_size(&set) > 0)
	{
		if (!list_remove_next(&set, NULL, (void **)&data))
			free(data);
	}

	print_set(&set);

	set_init(&set1, match_int, free);
	set_init(&set2, match_int, free);

	for (idx = 0; idx < 10; idx++)
	{
		if (!(data = (int *)malloc(sizeof(int))))
			return -1;
		*data = idx + 1;
		ret = set_insert(&set1, data);
		if (ret < 0)
			return -1;
		else if (ret == 1)
			free(data);

		if (idx == 5 || idx == 6 || idx == 7){
			if (!(data = (int *)malloc(sizeof(int))))
				return -1;
			*data = idx * 10;
			ret = set_insert(&set2, data);
			if (ret < 0)
				return -1;
			else if (ret == 1)
				free(data);
		}

		if (idx == 3 || idx == 1){
			if (!(data = (int *)malloc(sizeof(int))))
				return -1;

			*data = idx;
			ret = set_insert(&set2, data);
			if (ret < 0)
				return -1;
			else if (ret == 1)
				free(data);
		}
	}

	fprintf(stdout, "Set 1 for testing unions, intersections, and differences\n");
	print_set(&set1);
	fprintf(stdout, "Set 2 for testing unions, intersections, and differences\n");
	print_set(&set2);

	fprintf(stdout, "determining the union of the 2 sets\n");
	if (set_union(&set, &set1, &set2))
		return -1;
	print_set(&set);

	fprintf(stdout, "Destroying the union\n");
	set_destroy(&set);

	fprintf(stdout, "Determining the intersection of the two sets\n");
	if (set_intersection(&set, &set1, &set2))
	   return 1;
	print_set(&set);
	
	fprintf(stdout, "Testing whether the intersection equals Set 1...Value=%d "
	   "(0=OK)\n", set_is_equal(&set, &set1));

	fprintf(stdout, "Testing whether Set 1 equals itself...Value=%d (1=OK)\n",
	   set_is_equal(&set1, &set1));

	fprintf(stdout, "Testing whether the intersection is a subset of Set 1..."
	   "Value=%d (1=OK)\n", set_is_subset(&set, &set1));

	fprintf(stdout, "Testing whether Set 2 is a subset of Set 1...Value=%d "
	   "(0=OK)\n", set_is_subset(&set2, &set1));

	fprintf(stdout, "Destroying the intersection\n");
	set_destroy(&set);

	fprintf(stdout, "Determining the difference of the two sets\n");

	if (set_difference(&set, &set1, &set2) != 0)
	   return 1;

	print_set(&set);

	i = 3;
	fprintf(stdout, "Testing whether %03d is in difference...Value=%d (0=OK)\n",i,
	   set_is_member(&set, &i));

	i = 5;
	fprintf(stdout, "Testing whether %03d is in difference...Value=%d (1=OK)\n",i,
	   set_is_member(&set, &i));

	/*****************************************************************************
	*                                                                            *
	*  Destroy the sets.                                                         *
	*                                                                            *
	*****************************************************************************/

	fprintf(stdout, "Destroying the sets\n");
	set_destroy(&set);
	set_destroy(&set1);
	set_destroy(&set2);

	return 0;
}

